import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.dates as mdates
import os
from datetime import datetime, timedelta

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 定义常量 - 保存结果的目录
RESULTS_DIR = r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\results"


def load_erp_data():
    """加载ERP订单数据"""
    # 定义可能的文件路径
    possible_paths = [
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\data\erp_order_data.xlsx",
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\erp_order_data.xlsx"
    ]

    for path in possible_paths:
        if os.path.exists(path):
            try:
                df = pd.read_excel(path)
                # 确保日期格式正确
                if 'order_time' in df.columns:
                    df['order_time'] = pd.to_datetime(df['order_time'])
                print(f"✓ 数据加载成功: {path}")
                return df
            except Exception as e:
                print(f"读取 {path} 失败: {e}")
                continue

    raise FileNotFoundError("未找到erp_order_data.xlsx文件，请确认文件是否存在或路径是否正确")


def create_gantt_chart():
    """创建甘特图：2025年化妆品类目采购项目进度"""
    # 加载数据
    df = load_erp_data()

    # 获取数据中的时间范围
    if 'order_time' in df.columns:
        min_date = df['order_time'].min()
        max_date = df['order_time'].max()
        print(f"数据时间范围: {min_date} - {max_date}")
    else:
        # 如果数据中没有时间信息，使用默认时间范围
        min_date = pd.Timestamp('2024-10-01')
        max_date = pd.Timestamp('2025-10-21')
        print("警告：数据中没有时间信息，使用默认时间范围")

    # 设置项目阶段
    tasks = [
        "制定计划", "方案设计", "资源调配", "第一阶段",
        "第二阶段", "第三阶段", "项目总结"
    ]

    # 设置每个阶段的开始和结束日期（基于数据时间范围）
    total_days = (max_date - min_date).days

    # 计算各阶段的时间分配
    stage_durations = [total_days * 0.1, total_days * 0.15, total_days * 0.2,
                       total_days * 0.25, total_days * 0.2, total_days * 0.1,
                       total_days * 0.1]

    # 计算各阶段的开始和结束日期
    start_dates = []
    end_dates = []
    current_date = min_date

    for duration in stage_durations:
        start_dates.append(current_date)
        end_dates.append(current_date + timedelta(days=int(duration)))
        current_date = end_dates[-1] + timedelta(days=1)

    # 设置完成百分比（模拟数据）
    completion_rates = [0.51, 0.32, 0.21, 0.85, 0.36, 0.68, 0.68]

    # 创建图形 - 深色背景
    fig, ax = plt.subplots(figsize=(14, 9), facecolor='#1A1A2E')
    ax.set_facecolor('#1A1A2E')

    # 创建水平条形图
    y_pos = np.arange(len(tasks))

    # 绘制进度条
    for i in range(len(tasks)):
        # 绘制总进度条
        total_width = (end_dates[i] - start_dates[i]).days

        # 绘制已完成部分
        completed_width = total_width * completion_rates[i]

        # 绘制未完成部分
        remaining_width = total_width - completed_width

        # 绘制已完成部分（浅蓝色）
        ax.barh(y_pos[i], completed_width, height=0.6, left=(start_dates[i] - min_date).days,
                color='#4BB5C2', alpha=0.9)

        # 绘制进度百分比标签
        mid_point = (start_dates[i] - min_date).days + completed_width / 2
        ax.text(mid_point, y_pos[i], f'{int(completion_rates[i] * 100)}%',
                ha='center', va='center', color='white', fontweight='bold')

        # 如果有剩余进度，绘制灰色部分
        if remaining_width > 0:
            ax.barh(y_pos[i], remaining_width, height=0.6, left=(start_dates[i] - min_date).days + completed_width,
                    color='#555555', alpha=0.7)

    # 设置X轴为日期
    ax.set_xlim(0, (max_date - min_date).days)
    ax.set_ylim(-0.5, len(tasks) - 0.5)

    # 创建日期刻度
    date_ticks = []
    date_labels = []

    # 按时间间隔生成刻度
    current_date = min_date
    while current_date <= max_date:
        date_ticks.append((current_date - min_date).days)
        date_labels.append(current_date.strftime('%Y/%m'))
        current_date += timedelta(days=30)  # 每30天一个刻度

    # 设置X轴刻度
    ax.set_xticks(date_ticks)
    ax.set_xticklabels(date_labels, color='#E0E0E0', fontsize=10)

    # 设置Y轴标签
    ax.set_yticks(y_pos)
    ax.set_yticklabels(tasks, color='#E0E0E0', fontsize=12, fontweight='bold')

    # 设置标题 - 关键修改：调整标题位置，避免与图表内容重叠
    title_main = '2025年化妆品类目采购项目进度'
    ax.set_title(title_main, fontsize=20, fontweight='bold', pad=20, color='#FFFFFF')

    # 添加副标题（放在主标题下方，确保不重叠）
    # 分析最近的趋势
    overall_progress = sum(
        [rate * (end_dates[i] - start_dates[i]).days for i, rate in enumerate(completion_rates)]) / sum(
        [(end_dates[i] - start_dates[i]).days for i in range(len(tasks))])

    # 找出进度最快的阶段
    fastest_stage_idx = np.argmax(completion_rates)
    slowest_stage_idx = np.argmin(completion_rates)

    # 生成副标题
    subtitle = f'项目整体进度{int(overall_progress * 100)}%，{tasks[fastest_stage_idx]}阶段进度最快，{tasks[slowest_stage_idx]}阶段进度最慢'

    # 关键修改：将副标题向上移动，确保不遮挡其他元素
    ax.text(0.5, 1.1, subtitle,
            ha='center', va='center', transform=ax.transAxes,
            fontsize=14, fontweight='bold', color='#FFFFFF',
            bbox=dict(boxstyle='round,pad=0.3', facecolor='#2C3E50', edgecolor='none', alpha=0.7),
            zorder=10)  # 确保副标题在顶部

    # 设置轴标签
    ax.set_xlabel('时间', fontsize=14, color='#E0E0E0')
    ax.set_ylabel('项目阶段', fontsize=14, color='#E0E0E0')

    # 设置网格线
    ax.grid(axis='x', linestyle='--', alpha=0.3, color='#4A4A6A')

    # 美化坐标轴
    for spine in ax.spines.values():
        spine.set_color('#4A4A6A')
        spine.set_linewidth(2)

    # 设置坐标轴颜色
    ax.tick_params(axis='x', colors='#E0E0E0')
    ax.tick_params(axis='y', colors='#E0E0E0')

    # 添加数据来源
    latest_date = df['order_time'].max() if 'order_time' in df.columns else max_date
    latest_date_str = latest_date.strftime('%Y.%m.%d')
    source_text = f'*注：数据来源于公司销售系统，统计日期截至{latest_date_str}'
    ax.text(0.02, 0.02, source_text, transform=ax.transAxes,
            fontsize=10, color='#B0B0B0', alpha=0.7, va='bottom')

    # 调整布局
    plt.tight_layout()

    # 确保结果目录存在
    os.makedirs(RESULTS_DIR, exist_ok=True)
    # 保存图片
    output_path = os.path.join(RESULTS_DIR, '10_甘特图.png')
    plt.savefig(output_path, dpi=300, bbox_inches='tight',
                facecolor='#1A1A2E', edgecolor='none')

    plt.show()

    # 数据分析
    print("甘特图数据分析：")
    print(f"- 项目时间范围：{min_date.strftime('%Y-%m-%d')} 至 {max_date.strftime('%Y-%m-%d')}")
    print(f"- 项目阶段数：{len(tasks)}个")

    # 找出进度最慢的阶段
    min_progress = min(completion_rates)
    min_index = completion_rates.index(min_progress)
    print(f"- 进度最慢的阶段：{tasks[min_index]}，进度{int(min_progress * 100)}%")

    # 找出进度最快的阶段
    max_progress = max(completion_rates)
    max_index = completion_rates.index(max_progress)
    print(f"- 进度最快的阶段：{tasks[max_index]}，进度{int(max_progress * 100)}%")

    return fig, ax


# 执行代码
if __name__ == "__main__":
    try:
        fig, ax = create_gantt_chart()
    except Exception as e:
        print(f"图表生成失败: {e}")
        raise